using System;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Collections;
using System.Collections.Generic;
using System.Security.Principal;

using SBPweb.RIA.Server.Common.Patterns;

namespace SBPweb.RIA.Server.Common.Web
{
    
	/// <summary>
	/// Class of SessionManager
	/// </summary>
    public class SessionManager : IEnumerable<KeyValuePair<string, object>>
    {

        #region Private members

        private const string KEY_ASP_NET_SessionID = "ASP.NET_SessionID";

        private static LockHelper lh = new LockHelper("SessionManager");
        private static SingletonHelper<SessionManager> sh = new SingletonHelper<SessionManager>();

        private HttpSessionState sess = null;

        protected HttpSessionState session
        {
            get
            {
                if (sess != null || HttpContext.Current == null)
                {
                    return sess;
                }
                return HttpContext.Current.Session;
            }
        }

        private static Dictionary<string, object> appDictionary = new Dictionary<string, object>();

        #endregion

        #region Constructor logic

        static SessionManager()
        {
        }

        public SessionManager()
        {
        }

        private SessionManager(HttpSessionState state)
        {
            sess = state;
        }

        #endregion

        #region Properties

        public static SessionManager Session
        {
            get
            {
                return sh.Instance;
            }
        }

        /// <summary>
        /// Is available?
        /// </summary>
        public bool IsAvailable
        {
            get
            {
                return session != null;
            }
        }

        /// <summary>
        /// ID of the session
        /// </summary>
        public string SessionIdentifier
        {
            get
            {
                if (IsAvailable)
                {
                    return session.SessionID;
                }
                return null;
            }
        }

        #endregion

        #region Public methods

        public static void PublicateSession()
        {
            PublicateSession(Session);
        }

        public static void PublicateSession(SessionManager session)
        {
            using (lh.GetLock())
            {
                appDictionary[session.SessionIdentifier] = session;
            }
        }

        public static SessionManager ReplicateSession(string sessionId)
        {
            using (lh.GetLock())
            {
                return appDictionary[sessionId] as SessionManager;
            }
        }

        public static void RevokeSession()
        {
            RevokeSession(Session.SessionIdentifier);
        }

        public static void RevokeSession(string sessionId)
        {
            using (lh.GetLock())
            {
                appDictionary.Remove(sessionId);
            }
        }

        /// <summary>
        /// Abandon
        /// </summary>
        public void Abandon()
        {
            RemoveAppStateValues();
            session.Abandon();
        }

        /// <summary>
        /// Remove application state values
        /// </summary>
        public void RemoveAppStateValues()
        {
            if (session == null)
            {
                GCAppStateValues();
            }
        }

        /// <summary>
        /// GCAppStateValues
        /// </summary>
        public static void GCAppStateValues()
        {
            ArrayList gcItems = new ArrayList();

            using (lh.GetLock())
            {
                foreach (string key in appDictionary.Keys)
                {
                    object obj = appDictionary[key];

                    if (obj is IPrincipal)
                    {
                        if (!(obj as IPrincipal).Identity.IsAuthenticated)
                        {
                            gcItems.Add(key);
                        }
                    }
                }

                foreach (string key in gcItems)
                {
                    appDictionary.Remove(key);
                }
            }
        }

        /// <summary>
        /// Get from the session
        /// </summary>
        /// <typeparam name="T">type</typeparam>
        /// <param name="key">key</param>
        /// <returns>item</returns>
        public T Get<T>(string key)
        {
            if (session == null || session[key] == null)
            {
                return default(T);
            }
            return (T)session[key];
        }

        /// <summary>
        /// Put to the session
        /// </summary>
        /// <typeparam name="T">type</typeparam>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public void Put<T>(string key, T value)
        {
            if (session != null)
            {
                session.Add(key, value);
            }
        }

        /// <summary>
        /// Get from the session
        /// </summary>
        /// <typeparam name="T">type</typeparam>
        /// <param name="sessionId">id</param>
        /// <param name="key">key</param>
        /// <returns>item</returns>
        public T Get<T>(string sessionId, string key)
        {
            using (lh.GetLock())
            {
                if (!appDictionary.ContainsKey(sessionId))
                {
                    return default(T);
                }
                Dictionary<string, object> dict = appDictionary[sessionId] as Dictionary<string, object>;

                return (T)dict[key];
            }
        }

        /// <summary>
        /// Put in the session
        /// </summary>
        /// <typeparam name="T">type</typeparam>
        /// <param name="sessionId">id</param>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public void Put<T>(string sessionId, string key, T value)
        {
            using (lh.GetLock())
            {
                Dictionary<string, object> dict;
                if (!appDictionary.ContainsKey(sessionId))
                {
                    dict = new Dictionary<string, object>();
                    appDictionary.Add(sessionId, dict);
                }
                else
                {
                    dict = appDictionary[sessionId] as Dictionary<string, object>;
                }

                if (!dict.ContainsKey(key))
                {
                    dict.Add(key, value);
                }
                else
                {
                    dict[key] = value;
                }
            }
        }

        /// <summary>
        /// Remove item
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="key">key</param>
        public void Remove<T>(string key)
        {
            if (session != null)
            {
                session.Remove(key);
            }
        }

        /// <summary>
        /// Remove item
        /// </summary>
        /// <typeparam name="T">Type</typeparam>
        /// <param name="sessionId">id</param>
        /// <param name="key">key</param>
        public void Remove<T>(string sessionId, string key)
        {
            using (lh.GetLock())
            {
                if (appDictionary.ContainsKey(key))
                {
                    appDictionary.Remove(key);
                }
            }
        }
        #region IEnumerable<KeyValuePair<string,object>> Members

        public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            if (session != null)
            {
                IList<KeyValuePair<string, object>> ret = new List<KeyValuePair<string, object>>();
                foreach (string key in session.Contents)
                {
                    ret.Add(new KeyValuePair<string, object>(key, session[key]));
                }
                return ret.GetEnumerator();
            }
            else
            {
                using (lh.GetLock())
                {
                    Dictionary<string, object> dic = (Dictionary<string, object>)appDictionary[SessionIdentifier];
                    return dic.GetEnumerator();
                }
            }
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return (IEnumerator)GetEnumerator();
        }

        #endregion

        #endregion

        #region Private helper methods

        private string GenerateSessionUniqueKeyForKey(string key)
        {
            string sessionId = HttpContext.Current.Request.Params[KEY_ASP_NET_SessionID];
            if ((string.IsNullOrEmpty(sessionId)) && session != null)
            {
                sessionId = session.SessionID;
            }

            return sessionId + "_" + key;
        }

        #endregion

    }

}